package com.yequan.redis;

import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Random;

/**
 * @author yq
 * @date 2020/06/01
 */
public class RedisLock {

    ///protected final Log logger = LogFactory.getLog(getClass());
    protected final Logger logger = Logger.getLogger(getClass());//"debug"

    // 加锁标志
    public static final String LOCKED = "TRUE";
    public static final long ONE_MILLI_NANOS = 1000000L;
    // 默认超时时间（毫秒）
    public static final long DEFAULT_TIME_OUT = 10;
    //public static final long DEFAULT_TIME_OUT = 300;
    //public static final long DEFAULT_TIME_OUT = 5000;
    public static JedisPool pool;
    public static final Random r = new Random();
    // 锁的超时时间（秒），过期删除
//	public static final int EXPIRE = 5 * 60;
    //设置过期时间为15秒
    public static final int EXPIRE = 250 * 60;
    static {
        pool = new JedisPool("127.0.0.1", 6379);
    }
    private Jedis jedis;
    private String key;
    // 锁状态标志
    private boolean locked = false;

    public RedisLock(String key) {
        this.key = key;
        this.jedis = pool.getResource();
    }

    public boolean lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= ONE_MILLI_NANOS;
        try {
            while ((System.nanoTime() - nano) < timeout) {
                if (jedis.setnx(key, LOCKED) == 1) {
                    jedis.expire(key, EXPIRE);
                    locked = true;
                    logger.info(">>>locked="+key+ Thread.currentThread().getName());
                    return locked;
                }
                // 短暂休眠，nano避免出现活锁
                Thread.sleep(3, r.nextInt(500));
            }
        } catch (Exception e) {
            logger.error("===exception"+key+e.getMessage() +e.getLocalizedMessage() + Thread.currentThread().getName());
            e.printStackTrace();
        }
        return false;
    }

    public boolean lock() {
        return lock(DEFAULT_TIME_OUT);
    }

    // 无论是否加锁成功，必须调用
    public void unlock() {
        try {
            if (locked){
                jedis.del(key);

                logger.info("<<<unlocked="+key+ Thread.currentThread().getName());
            }
        } finally {
            pool.returnResource(jedis);
        }
    }

    public static void test() throws InterruptedException {
        String key = "key123";
        RedisLock redisLock = new RedisLock(key);
        try {
            if (redisLock.lock(30000)) {
                for(int i=0;i<100;i++){
                    System.out.println(i);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            redisLock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
//		RedisLock lock = new RedisLock(null);
        test();

    }

}
